package com.ctvit.cch.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.ctvit.cch.core.enums.GenerateStatusEnum;
import com.ctvit.cch.core.mapper.CreativeScriptDesignMapper;
import com.ctvit.cch.core.mapper.CreativeScriptSceneMapper;
import com.ctvit.cch.core.mapper.CreativeShotDesignMapper;
import com.ctvit.cch.core.mapper.CreativeShotFrameMapper;
import com.ctvit.cch.core.mapper.CreativeTopicMapper;
import com.ctvit.cch.core.pojo.domain.CreativeScriptDesign;
import com.ctvit.cch.core.pojo.domain.CreativeScriptScene;
import com.ctvit.cch.core.pojo.domain.CreativeShotDesign;
import com.ctvit.cch.core.pojo.domain.CreativeShotFrame;
import com.ctvit.cch.core.pojo.domain.CreativeTopic;
import com.ctvit.cch.core.pojo.dto.creative.CreativeShotDesignGenerateSidDTO;
import com.ctvit.cch.core.pojo.dto.creative.CreativeShotDesignRegenerateSidDTO;
import com.ctvit.cch.core.pojo.vo.creative.CreativeShotFrameGetVO;
import com.ctvit.cch.core.pojo.vo.creative.CreativeShotFrameListVO;
import com.ctvit.cch.core.service.ICreativeShotDesignService;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

/**
 * 分镜设计Service业务层处理
 *
 * @author heyingcheng
 * @date 2025/10/11
 */
@Service
public class CreativeShotDesignServiceImpl extends ServiceImpl<CreativeShotDesignMapper, CreativeShotDesign>
        implements ICreativeShotDesignService {

    private final CreativeTopicMapper creativeTopicMapper;

    private final CreativeScriptDesignMapper creativeScriptDesignMapper;

    private final CreativeScriptSceneMapper creativeScriptSceneMapper;

    private final CreativeShotFrameMapper creativeShotFrameMapper;

    public CreativeShotDesignServiceImpl(CreativeTopicMapper creativeTopicMapper,
            CreativeScriptDesignMapper creativeScriptDesignMapper,
            CreativeScriptSceneMapper creativeScriptSceneMapper, CreativeShotFrameMapper creativeShotFrameMapper) {
        this.creativeTopicMapper = creativeTopicMapper;
        this.creativeScriptDesignMapper = creativeScriptDesignMapper;
        this.creativeScriptSceneMapper = creativeScriptSceneMapper;
        this.creativeShotFrameMapper = creativeShotFrameMapper;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean generate(CreativeShotDesignGenerateSidDTO dto) {
        final String scriptId = dto.getScriptId();

        CreativeScriptDesign creativeScriptDesign = creativeScriptDesignMapper.selectById(scriptId);
        Assert.isTrue(GenerateStatusEnum.SUCCESS.name().equals(creativeScriptDesign.getGenerateStatus()), "脚本设计未完成");
        Assert.isTrue(GenerateStatusEnum.WAIT.name().equals(creativeScriptDesign.getShotStatus())
                || GenerateStatusEnum.FAILURE.name().equals(creativeScriptDesign.getShotStatus()),
                "分镜设计已进行中");

        final String shotId = IdWorker.getIdStr();
        final String topicId = creativeScriptDesign.getTopicId();

        CreativeShotDesign creativeShotDesign = new CreativeShotDesign();
        creativeShotDesign.setShotId(shotId);
        creativeShotDesign.setScriptId(scriptId);
        creativeShotDesign.setTopicId(topicId);
        creativeShotDesign.setAdditionalContent(StringUtils.defaultString(dto.getAdditionalContent()));
        creativeShotDesign.setGenerateStatus(GenerateStatusEnum.QUEUED.name());
        boolean result = save(creativeShotDesign);
        Assert.isTrue(result, "分镜设计保存失败");

        result = SqlHelper
                .retBool(creativeScriptDesignMapper.update(new LambdaUpdateWrapper<CreativeScriptDesign>()
                        .eq(CreativeScriptDesign::getScriptId, scriptId)
                        .in(CreativeScriptDesign::getShotStatus,
                                Arrays.asList(GenerateStatusEnum.WAIT.name(), GenerateStatusEnum.FAILURE.name()))
                        .set(CreativeScriptDesign::getShotStatus, GenerateStatusEnum.QUEUED.name())
                        .set(CreativeScriptDesign::getShotId, shotId)));
        Assert.isTrue(result, "脚本分镜设计状态更新失败");

        result = SqlHelper
                .retBool(creativeScriptSceneMapper.update(new LambdaUpdateWrapper<CreativeScriptScene>()
                        .eq(CreativeScriptScene::getScriptId, scriptId)
                        .set(CreativeScriptScene::getShotStatus, GenerateStatusEnum.QUEUED.name())));
        Assert.isTrue(result, "场景分镜设计状态更新失败");

        result = SqlHelper.retBool(creativeTopicMapper.update(new LambdaUpdateWrapper<CreativeTopic>()
                .eq(CreativeTopic::getTopicId, topicId)
                .eq(CreativeTopic::getScriptStatus, GenerateStatusEnum.SUCCESS.name())
                .set(CreativeTopic::getShotStatus, GenerateStatusEnum.QUEUED.name())
                .set(CreativeTopic::getShotTime, LocalDateTime.now())));
        Assert.isTrue(result, "选题分镜设计状态更新失败");

        return result;
    }

    @Override
    public boolean regenerate(CreativeShotDesignRegenerateSidDTO dto) {
        return generate(new CreativeShotDesignGenerateSidDTO(dto.getScriptId(), dto.getAdditionalContent()));
    }

    private CreativeShotFrameGetVO assignCreativeShotDesign(CreativeScriptDesign creativeScriptDesign) {
        CreativeShotFrameGetVO vo = new CreativeShotFrameGetVO();
        BeanUtils.copyProperties(Objects.requireNonNull(creativeScriptDesign), vo);

        if (GenerateStatusEnum.SUCCESS.name().equals(creativeScriptDesign.getShotStatus())) {
            List<CreativeShotFrame> shotDesignList = creativeShotFrameMapper
                    .selectList(new LambdaQueryWrapper<CreativeShotFrame>()
                            .eq(CreativeShotFrame::getShotId, creativeScriptDesign.getShotId())
                            .orderByAsc(CreativeShotFrame::getSceneIndex, CreativeShotFrame::getFrameIndex));

            List<CreativeShotFrameListVO> shotDesigns = shotDesignList.stream().map(item -> {
                CreativeShotFrameListVO csflVo = new CreativeShotFrameListVO();
                BeanUtils.copyProperties(Objects.requireNonNull(item), csflVo);
                return csflVo;
            }).collect(Collectors.toList());
            vo.setFrames(shotDesigns);
        }

        return vo;
    }

    @Override
    public CreativeShotFrameGetVO getByScriptId(String scriptId) {
        CreativeScriptDesign creativeScriptDesign = creativeScriptDesignMapper.selectById(scriptId);
        Assert.notNull(creativeScriptDesign, "脚本设计不存在");

        return assignCreativeShotDesign(creativeScriptDesign);
    }

    @Override
    public CreativeShotFrameGetVO getByTopicId(String topicId) {
        CreativeTopic tOne = creativeTopicMapper.selectById(topicId);
        Assert.notNull(tOne, "选题不存在");
        String scriptId = tOne.getScriptId();
        Assert.isTrue(StringUtils.isNotBlank(scriptId), "选题未生成脚本设计");

        CreativeScriptDesign creativeScriptDesign = creativeScriptDesignMapper.selectOne(
                new LambdaQueryWrapper<CreativeScriptDesign>().eq(CreativeScriptDesign::getScriptId, scriptId));
        Assert.notNull(creativeScriptDesign, "脚本设计不存在");

        return assignCreativeShotDesign(creativeScriptDesign);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateGenerateStatus(String topicId, String scriptId, String shotId, String status) {
        boolean result = update(new LambdaUpdateWrapper<CreativeShotDesign>()
                .eq(CreativeShotDesign::getShotId, shotId)
                .set(CreativeShotDesign::getGenerateStatus, status));
        Assert.isTrue(result, "分镜设计生成状态更新失败");

        result = SqlHelper.retBool(creativeScriptDesignMapper.update(new LambdaUpdateWrapper<CreativeScriptDesign>()
                .eq(CreativeScriptDesign::getScriptId, scriptId)
                .set(CreativeScriptDesign::getShotStatus, status)));
        Assert.isTrue(result, "脚本分镜设计状态更新失败");

        result = SqlHelper.retBool(creativeTopicMapper.update(new LambdaUpdateWrapper<CreativeTopic>()
                .eq(CreativeTopic::getTopicId, topicId)
                .set(CreativeTopic::getShotStatus, status)
                .set(CreativeTopic::getShotTime, LocalDateTime.now())));
        Assert.isTrue(result, "选题分镜设计状态更新失败");

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean completeGenerateDesign(String topicId, String scriptId, String shotId) {
        List<CreativeScriptScene> scriptSceneList = creativeScriptSceneMapper
                .selectList(new LambdaQueryWrapper<CreativeScriptScene>()
                        .select(CreativeScriptScene::getSceneId, CreativeScriptScene::getShotStatus));

        Map<String, List<String>> statusToSceneIdsMap = scriptSceneList.stream()
                .collect(Collectors.groupingBy(
                        CreativeScriptScene::getShotStatus,
                        Collectors.mapping(CreativeScriptScene::getSceneId, Collectors.toList())));

        if (statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.ING.name())
                || statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.QUEUED.name())) {
            return updateGenerateStatus(topicId, scriptId, shotId, GenerateStatusEnum.QUEUED.name());
        }

        if (statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.FAILURE.name())) {
            return updateGenerateStatus(topicId, scriptId, shotId, GenerateStatusEnum.FAILURE.name());
        }

        if (statusToSceneIdsMap.keySet().contains(GenerateStatusEnum.SUCCESS.name())
                && statusToSceneIdsMap.keySet().size() == 1) {
            return updateGenerateStatus(topicId, scriptId, shotId, GenerateStatusEnum.SUCCESS.name());
        }

        return false;
    }

}